﻿using DreamCMS.BLL.Factory;
using DreamCMS.BLL.Factory.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace DreamCMS.BLL.Factory
{
    /// <summary>
    /// 数据访问对象工厂
    /// </summary>
    public sealed class DataAccessFactory
    {
        private static readonly string dalAssemblyName = "DreamCMS.DAL";
        private static readonly string dalNameSpacePrefix = dalAssemblyName + ".DataAccessObject.";
        private static object lockHelper = new object();

        private static IStatisticDAO statisticDAO = null;
        private static ISiteSettingDAO siteSettingDAO = null;
        private static IPostDAO postDAO = null;
        private static IUserDAO userDAO = null;
        private static ICategoryDAO catDAO = null;
        private static ITagDAO tagDAO = null;
        private static ICommentDAO comDAO = null;

        /// <summary>
        /// 创建站点统计DAO对象
        /// </summary>
        /// <returns>返回StatisticDAO对象</returns>
        public static IStatisticDAO CreateStatisticDAO()
        {
            if(statisticDAO!=null)
            {
                return statisticDAO;
            }
            string className = dalNameSpacePrefix + "StatisticDAO";
            return  CreateInstance<IStatisticDAO>(statisticDAO, className, dalAssemblyName);
        }
        /// <summary>
        /// 创建站点设置DAO对象
        /// </summary>
        /// <returns>返回SiteSettingDAO对象</returns>
        public static ISiteSettingDAO CreateSiteSettingDAO()
        {
            if(siteSettingDAO!=null)
            {
                return siteSettingDAO;
            }
            string className = dalNameSpacePrefix + "SiteSettingDAO";
            return CreateInstance<ISiteSettingDAO>(siteSettingDAO, className, dalAssemblyName);
        }
        /// <summary>
        /// 创建一个文章DAO对象
        /// </summary>
        /// <returns>PostDAO对象</returns>
        public static IPostDAO CreatePostDAO()
        {
            if(postDAO!=null)
            {
                return postDAO;
            }
            string className = dalNameSpacePrefix + "PostDAO";
            return CreateInstance<IPostDAO>(postDAO, className, dalAssemblyName);
        }
        /// <summary>
        /// 创建UserDAO数据访问对象
        /// </summary>
        /// <returns>返回IUserDAO接口类型的UserDAO对象</returns>
        public static IUserDAO CreateUserDAO()
        {
            if(userDAO!=null)
            {
                return userDAO;
            }
            string className = dalNameSpacePrefix + "UserDAO";
            return CreateInstance<IUserDAO>(userDAO, className, dalAssemblyName);
        }
        public static ICategoryDAO CreateCategoryDAO()
        {
            if(catDAO!=null)
            {
                return catDAO;
            }
            return CreateInstance<ICategoryDAO>(catDAO, dalNameSpacePrefix + "CategoryDAO", dalAssemblyName);
        }

        public static ITagDAO CreateTagDAO()
        {
            if(tagDAO!=null)
            {
                return tagDAO;
            }
            return CreateInstance<ITagDAO>(tagDAO, dalNameSpacePrefix + "TagsDAO", dalAssemblyName);
        }

        public static ICommentDAO CreateCommentDAO()
        {
            if (comDAO != null)
            {
                return comDAO;
            }
            return CreateInstance<ICommentDAO>(comDAO, dalNameSpacePrefix + "CommentDAO", dalAssemblyName);
        }

        /// <summary>
        /// 类内部使用，用来根据程序集和类名字符串来创建未引用的DAL层的类。（反射）
        /// </summary>
        /// <typeparam name="T">待创建的DAO类类型</typeparam>
        /// <param name="instance">本工厂内部的实例字段</param>
        /// <param name="className">类名（含路径）</param>
        /// <param name="path">类路径</param>
        /// <returns></returns>
        private static T CreateInstance<T>(T instance,string className,string assemblyName)
        {
            if(instance==null)
            {
                //崔：此处要用锁来实现临界区，避免此时并发环境下其他用户线程来访问本方法，从而导致给instance多次实例化。造成内存崩溃。
                lock(lockHelper)
                {
                    if(instance==null)
                    {
                        //instance = (T)Assembly.Load(path).CreateInstance(className);//此处是否可以直接调用DAL层的DAO类来实例化呢。由于我把DataAccesFactory搬到了DAL层，于是动态加载或许就显得多此一举了。。。
                        instance = (T)(Assembly.Load(assemblyName).CreateInstance(className));
                    }
                }
            }
            return instance;
        }
    }
}
